home *** CD-ROM | disk | FTP | other *** search
- /*
- dsniff.c
-
- sniff mail on a network, saving messages in Berkeley mbox format
- (for processing with mail -f, pine, mutt, whatever).
- this is for demonstration purposes and educational use only.
-
- TODO: Apparently-To: forgery checks, regex support, POP/IMAP
- sniffing, mail.local-style locking, etc.
-
- Copyright (c) 1999 Dug Song <dugsong@monkey.org>
- All rights reserved, all wrongs reversed.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- $Id: mailsnarf.c,v 1.25 2000/05/16 18:48:01 dugsong Exp $ */
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <arpa/inet.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <time.h>
- #include <nids.h>
-
- #include "version.h"
-
- /* bogus SMTP state machine */
- enum {
- S_NONE = 0,
- S_HELO,
- S_MAIL,
- S_RCPT,
- S_DATA
- };
-
- struct msg_info {
- int smtp_state;
- char *from;
- char *to;
- };
-
- void
- usage(void)
- {
- fprintf(stderr, "Usage: mailsnarf [-i interface]\n");
- exit(1);
- }
-
- /* Locate substring in a binary string. */
- u_char *
- bufbuf(u_char *big, int blen, u_char *little, int llen)
- {
- u_char *p;
-
- for (p = big; p <= big + blen - llen; p++) {
- if (memcmp(p, little, llen) == 0)
- return (p);
- }
- return (NULL);
- }
-
- char *
- grep_mail_address(char *buf)
- {
- char *p, *q;
-
- if ((p = strchr(buf, '<')) != NULL) {
- p++;
- if ((q = strchr(p, '>')) != NULL)
- *q = '\0';
- if (strlen(p) > 0)
- return (strdup(p));
- }
- return (NULL);
- }
-
- int
- process_smtp_msg(struct msg_info *msg, char *buf, int len)
- {
- char *s, *e;
- int i, discard = 0;
- time_t t;
-
- if (msg->smtp_state != S_DATA) {
- /* Process SMTP commands. */
- for (s = buf; (e = bufbuf(s, len, "\r\n", 2)) != NULL; s = e + 2) {
- i = (e + 2) - s;
- discard += i; len -= i;
- *e = '\0';
-
- if (strncasecmp(s, "RSET", 4) == 0) {
- msg->smtp_state = S_HELO;
- }
- else if (msg->smtp_state == S_NONE &&
- (strncasecmp(s, "HELO", 4) == 0 ||
- strncasecmp(s, "EHLO", 4) == 0)) {
- msg->smtp_state = S_HELO;
- }
- else if (msg->smtp_state == S_HELO &&
- (strncasecmp(s, "MAIL ", 5) == 0 ||
- strncasecmp(s, "SEND ", 5) == 0 ||
- strncasecmp(s, "SAML ", 5) == 0)) {
- msg->from = grep_mail_address(s);
- msg->smtp_state = S_MAIL;
- }
- else if (msg->smtp_state == S_MAIL &&
- strncasecmp(s, "RCPT ", 5) == 0) {
- msg->to = grep_mail_address(s);
- msg->smtp_state = S_RCPT;
- }
- else if (msg->smtp_state == S_RCPT &&
- strncasecmp(s, "DATA", 4) == 0) {
- msg->smtp_state = S_DATA;
- break;
- }
- }
- buf = s;
- }
- /* Save until we get entire message. */
- if (msg->smtp_state == S_DATA &&
- (e = bufbuf(buf, len, "\r\n.\r\n", 5)) != NULL) {
- i = (e + 5) - buf;
- discard += i; len -= i;
- *e = '\0';
-
- /* Print message all at once. */
- t = time(NULL);
- printf("From %s %s", msg->from ? msg->from : "dsniff", ctime(&t));
-
- for (s = strtok(buf, "\n"); s != NULL; s = strtok(NULL, "\n")) {
- if (strncmp(s, "From ", 5) == 0)
- putchar('>');
- for (; *s != '\r' && *s != '\0'; s++)
- putchar(*s);
- putchar('\n');
- }
- putchar('\n');
- fflush(stdout);
-
- if (msg->to) {
- free(msg->to); msg->to = NULL;
- }
- if (msg->from) {
- free(msg->from); msg->from = NULL;
- }
- }
- return (discard);
- }
-
-
- /* XXX - Minimal SMTP FSM. We don't even consider server responses. */
- void
- sniff_smtp_client(struct tcp_stream *ts, struct msg_info **msg_save)
- {
- struct msg_info *msg;
- int i;
-
- /* Only handle SMTP client traffic. */
- if (ts->addr.dest != 25)
- return;
-
- switch (ts->nids_state) {
- case NIDS_JUST_EST:
- /* Collect data. */
- ts->server.collect = 1;
- if ((msg = malloc(sizeof(*msg))) == NULL)
- nids_params.no_mem("sniff_smtp_client");
-
- msg->smtp_state = S_NONE;
- msg->to = msg->from = NULL;
- *msg_save = msg;
- break;
-
- case NIDS_DATA:
- msg = *msg_save;
- if (ts->server.count_new != 0) {
- i = process_smtp_msg(msg, ts->server.data,
- ts->server.count - ts->server.offset);
- nids_discard(ts, i);
- }
- break;
-
- default:
- msg = *msg_save;
- if (ts->server.count != 0) {
- process_smtp_msg(msg, ts->server.data,
- ts->server.count - ts->server.offset);
- }
- if (msg->to) free(msg->to);
- if (msg->from) free(msg->from);
- free(msg);
- break;
- }
- }
-
- void
- null_syslog(int type, int errnum, struct ip *iph, void *data)
- {
- }
-
- int
- main(int argc, char *argv[])
- {
- int c;
-
- while ((c = getopt(argc, argv, "i:h?V")) != -1) {
- switch (c) {
- case 'i':
- nids_params.device = optarg;
- break;
- case 'V':
- fprintf(stderr, "Version: %s\n", VERSION);
- usage();
- break;
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 0)
- usage();
-
- nids_params.scan_num_hosts = 0;
- nids_params.syslog = null_syslog;
-
- if (!nids_init()) {
- fprintf (stderr, "%s\n", nids_errbuf);
- exit(1);
- }
- nids_register_tcp(sniff_smtp_client);
-
- nids_run();
-
- /* NOTREACHED */
-
- exit(0);
- }
-
- /* 5000. */
-